package com.example.test.fetch.fetcher;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.example.test.fetch.params.FetchParams;
import com.example.test.fetch.parser.BaseParser;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.net.HttpCookie;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
public class Fetcher<T> {

    protected FetchParams params;

    protected BaseParser<T> parser;

    @Getter
    protected List<T> result;

    public Fetcher(FetchParams params, BaseParser<T> parser) {
        this.params = params;
        this.parser = parser;
    }

    public void start() {
        this.result = CollUtil.newArrayList();
        this.fetch(1);
    }

    protected void fetch(int pageNum) {
        log.info("开始获取第{}页数据", pageNum);
        // 发送请求
        String responseBody = this.doFetch(buildHttpRequest(pageNum), params.getRetryCount());

        // 解析页面数据
        log.info("开始解析第{}页数据", pageNum);
        List<T> pageList = this.parser.parse(responseBody);
        log.info("第{}页数据解析完成", pageNum);
        if (CollUtil.isNotEmpty(pageList)) {
            result.addAll(pageList);
        }

        // 获取总页数
        if (this.parser.hasNext(responseBody)) {
            this.fetch(pageNum + 1);
        } else {
            log.info("数据获取完成");
        }
    }

    private HttpRequest buildHttpRequest(int pageNum) {
        // 构建请求参数
        Map<String, String> params1 = new LinkedHashMap<>(params.getParams());
        params1.put(params.getPageNumKey(), String.valueOf(pageNum));

        // 发送请求
        String fetchUrl = StrUtil.format("{}{}{}", params.getUrl(), (params.getUrl().contains("?") ? "&" : "?"), URLUtil.buildQuery(params1, Charset.defaultCharset()));
        HttpCookie[] cookies = ObjUtil.defaultIfNull(this.params.getCookies(), MapUtil.<String, String>empty())
                .entrySet()
                .stream()
                .map(entry -> {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    return new HttpCookie(key, value);
                }).toArray(HttpCookie[]::new);
        return HttpRequest.get(fetchUrl)
                .headerMap(this.params.getHeaders(), true)
                .cookie(cookies);
    }

    private String doFetch(HttpRequest httpRequest, int residueRetryCount) {
        try {
            int sleepSeconds = RandomUtil.randomInt(1, 10);
            log.info("进入请求等待, 等待时间: {}秒", sleepSeconds);
            TimeUnit.SECONDS.sleep(sleepSeconds);
            log.info("请求等待完成");
        } catch (InterruptedException e) {
            log.warn("休眠失败", e);
        }
        try {

            HttpResponse response = httpRequest.execute();
            String responseBody = response.body();
            parser.check(response.getStatus(), responseBody);
            return responseBody;
        } catch (Exception e) {
            if (residueRetryCount > 0) {
                return doFetch(httpRequest, residueRetryCount - 1);
            }
            throw e;
        }
    }

}
